package com.weiiew.common.GatawayAccess;

import com.weiiew.common.exception.GatewayAccessDeniedException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Objects;

@Aspect
@Component
public class GatewayAccessAspect {

    // 修改切入点表达式支持类和方法
    @Around("@within(gatewayAccess) || @annotation(gatewayAccess)")
    public Object checkAccess(ProceedingJoinPoint joinPoint, GatewayAccess gatewayAccess) throws Throwable {


        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder
                .getRequestAttributes())).getRequest();
        String gatewayHeader = request.getHeader("X-Gateway-Type");
        GatewayAccess.GatewayType currentType = GatewayAccess.GatewayType.valueOf(gatewayHeader.toUpperCase());

        // 1. 优先获取方法注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        GatewayAccess methodAnnotation = method.getAnnotation(GatewayAccess.class);

        // 2. 获取类注解
        GatewayAccess classAnnotation = joinPoint.getTarget().getClass().getAnnotation(GatewayAccess.class);

        //3. 合并注解
        GatewayAccess.GatewayType[] types;
        if (methodAnnotation != null) {
            types = methodAnnotation.value();
        }
        else if (classAnnotation != null){
            types = classAnnotation.value();
        }
        else types = new GatewayAccess.GatewayType[0];
        if (!checkPermission(currentType, types)){
            throw new GatewayAccessDeniedException("网关访问被拒绝");
        }
        return joinPoint.proceed();
    }

    private boolean checkPermission(GatewayAccess.GatewayType current, GatewayAccess.GatewayType[] required) {
        if (required.length == 0) return true;

        for (GatewayAccess.GatewayType type : required) {
            if (type == current) {
                 return true;
            }
        }
        return false;
    }
}